[Android] surfaceview中的canvas的变换和操作

surfaceView系列04

Posted by Aerber Zhou on 2017-06-18

个人觉得这篇很好.先放上来.

http://blog.csdn.net/harvic880925/article/details/39080931/

很多理解,这个博客中的图片很好的进行了每一步的解释.

零、canvas的概念

屏幕显示和每一步的canvas的操作不是同一个概念

每一次canvas.draw()系列函数,都是在屏幕显示的基础上重新建立一个新的图层,然后这个canvas.draw()的操作就是在这个新建的图层上完成,等在新图层上完成以后,再覆盖到屏幕显示 的图像上.

下面对上面的知识做一下总结:

1、每次调用canvas.drawXXXX系列函数来绘图进,都会产生一个全新的Canvas画布。

2、如果在DrawXXX前,调用平移、旋转等函数来对Canvas进行了操作,那么这个操作是不可逆的!每次产生的画布的最新位置都是这些操作后的位置。(关于Save()、Restore()的画布可逆问题的后面再讲)

3、在Canvas与屏幕合成时,超出屏幕范围的图像是不会显示出来的。

一、平移(translate)

注意:平移时是将 坐标原点为左上角,水平向右为x轴正方向,竖直向下为y轴正方向 的坐标系进行平移

void translate(float dx, float dy)

float dx:水平方向平移的距离,正数指向正方向(向右)平移的量,负数为向负方向(向左)平移的量

flaot dy:垂直方向平移的距离,正数指向正方向(向下)平移的量,负数为向负方向(向上)平移的量

二、旋转(Rotate)

rotate旋转操作的对象是画布,不是我们画的东西

同时,在旋转画布以后再进行draw()操作,draw()中的坐标系标准是以旋转完毕的那个画布为标准,而不是以屏幕的坐标系为标准.

void rotate(float degrees)

void rotate (float degrees, float px, float py)

第一个构造函数直接输入旋转的度数,正数是顺时针旋转,负数指逆时针旋转,它的旋转中心点是原点(0,0)

第二个构造函数除了度数以外,还可以指定旋转的中心点坐标(px,py)

三、缩放(scale )

public void scale (float sx, float sy)

public final void scale (float sx, float sy, float px, float py)

第二种没有使用,只讲第一种

float sx:水平方向伸缩的比例,假设原坐标轴的比例为n,不变时为1,在变更的X轴密度为n*sx;所以,sx为小数为缩小,sx为整数为放大

float sy:垂直方向伸缩的比例,同样,小数为缩小,整数为放大

注意:这里有X、Y轴的密度的改变,显示到图形上就会正好相同,比如X轴缩小,那么显示的图形也会缩小。一样的。

四、斜切(skew)

void skew (float sx, float sy)

参数说明:

float sx:将画布在x方向上倾斜相应的角度,sx倾斜角度的tan值,

float sy:将画布在y轴方向上倾斜相应的角度,sy为倾斜角度的tan值,

注意,这里全是倾斜角度的tan值,比如我们打算在X轴方向上倾斜60度,tan60=根号3,小数对应1.732

五、裁剪画布(clip系列函数)

裁剪画布是利用Clip系列函数,通过与Rect、Path、Region取交、并、差等集合运算来获得最新的画布形状。除了调用Save、Restore函数以外,这个操作是不可逆的,一但Canvas画布被裁剪,就不能再被恢复!

Clip系列函数如下:

boolean clipPath(Path path)

boolean clipPath(Path path, Region.Op op)

boolean clipRect(Rect rect, Region.Op op)

boolean clipRect(RectF rect, Region.Op op)

boolean clipRect(int left, int top, int right, int bottom)

boolean clipRect(float left, float top, float right, float bottom)

boolean clipRect(RectF rect)

boolean clipRect(float left, float top, float right, float bottom, Region.Op op)

boolean clipRect(Rect rect)

boolean clipRegion(Region region)

boolean clipRegion(Region region, Region.Op op)

**就如上面说的那样,一旦clip后,如果没有restore(),则后面画出来的图像,只有画在在刚刚的剪切区域中的图像显示出来.
同时,如果在clip后save,则保存的save的图像区域只有是clip出来的那块区域.其他部分没有保存下来.在这个情况下,后面再restore()出来的图层的大小区域就只有是裁剪区域,若在其他地方进行draw()操作,则只有画在在刚刚的剪切区域中的图像显示出来.
**

六、画布的保存与恢复(save()、restore())

前面我们讲的所有对画布的操作都是不可逆的,这会造成很多麻烦,比如,我们为了实现一些效果不得不对画布进行操作,但操作完了,画布状态也改变了,这会严重影响到后面的画图操作。如果我们能对画布的大小和状态(旋转角度、扭曲等)进行实时保存和恢复就最好了。

这小节就给大家讲讲画布的保存与恢复相关的函数——Save()、Restore()。

int save ()

void restore()

这两个函数没有任何的参数,很简单。

Save():每次调用Save()函数,都会把当前的画布的状态进行保存,然后放入特定的栈中;

restore():每当调用Restore()函数,就会把栈中最顶层的画布状态取出来,并按照这个状态恢复当前的画布,并在这个画布上做画。